use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use chrono::{DateTime, Local};
use serde_derive::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::db::pojo::pojo::{ImGroup, ImGroupStatus, ImGroupType, ImGroupUser, ImGroupUserStatus};
use crate::business::websocket::dto::json_serialize::{date_time_serde, date_time_serde_null};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupInfoListReq {

    #[serde(rename = "groupType")]
    pub group_type: GroupType,

    #[serde(rename = "startDate", with = "date_time_serde_null")]
    pub start_date: Option<DateTime<Local>>,

    #[serde(rename = "startServerId")]
    pub start_server_id: Option<String>,

    #[serde(rename = "pageSize")]
    pub page_size: usize,

    #[serde(rename = "groupId")]
    pub group_id: Option<String>,

    #[serde(rename = "sessionId")]
    pub session_id: Option<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupInfoItemList {
    #[serde(rename = "groupInfoItemList")]
    pub group_info_item_list: Vec<GroupInfoItem>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct GroupInfoItem {

    #[serde(rename = "sessionId")]
    pub session_id: Option<String>,

    #[serde(rename = "groupId")]
    pub group_id: String,

    #[serde(rename = "ownerId")]
    pub owner_id: String,

    #[serde(rename = "groupName")]
    pub group_name: Option<String>,

    #[serde(rename = "groupDesc")]
    pub group_desc: Option<String>,

    #[serde(rename = "groupUserSet")]
    pub group_user_set: HashSet<GroupUser>,

    #[serde(rename = "groupInfo")]
    pub group_info: Option<HashMap<String, String>>,
    pub status: GroupStatus,

    #[serde(rename = "firstLetter")]
    pub first_letter: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupUser {

    #[serde(rename = "userId")]
    pub user_id: String,

    #[serde(rename = "userName")]
    pub user_name: Option<String>,

    #[serde(rename = "isShowName")]
    pub is_show_name: bool,
    pub remark: Option<String>,

    #[serde(rename = "isWaking")]
    pub is_waking: bool,

    #[serde(rename = "isTop")]
    pub is_top: bool,

    #[serde(rename = "isDisturb")]
    pub is_disturb: bool,
    pub ext1: Option<String>,
    pub ext2: Option<String>,
    pub status: GroupUserStatus,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupCreateReq {

    #[serde(rename = "groupName")]
    pub group_name: String,

    #[serde(rename = "groupDesc")]
    pub group_desc: Option<String>,

    #[serde(rename = "userIdSet")]
    pub user_id_set: HashSet<String>,

    #[serde(rename = "groupId")]
    pub group_id: String,

    #[serde(rename = "sessionId")]
    pub session_id: Option<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupAddReq {

    #[serde(rename = "groupInfo")]
    pub group_info: HashMap<String, String>,

    #[serde(rename = "groupName")]
    pub group_name: String,

    #[serde(rename = "groupDesc")]
    pub group_desc: Option<String>,

    #[serde(rename = "userIdSet")]
    pub user_id_set: HashSet<String>,

    #[serde(rename = "groupId")]
    pub group_id: String,

    #[serde(rename = "sessionId")]
    pub session_id: Option<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GroupInfoReq {

    #[serde(rename = "groupId")]
    pub group_id: String,

    #[serde(rename = "sessionId")]
    pub session_id: Option<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

impl Hash for GroupUser {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.user_id.clone().hash(state);
    }
}

impl PartialEq<Self> for GroupUser {
    fn eq(&self, other: &Self) -> bool {
        self.user_id == other.user_id
    }
}

impl Eq for GroupUser {}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum GroupStatus {
    Disable = 2,
    Enable = 1,
    Dissolution = 3,
    Prohibition = 4,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum GroupUserStatus {
    Disable = 2,
    Enable = 1,
    Exit = 3,
    Prohibition = 4,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum GroupType {
    Chat = 1,
}




impl Into<ImGroup> for GroupInfoItem {
    fn into(self) -> ImGroup {
        let mut im_group_users = Vec::new();
        for group_user in self.group_user_set.into_iter() {
            let gu = ImGroupUser {
                id: None,
                group_id: 0,
                user_id: group_user.user_id,
                user_name: group_user.user_name,
                is_show_name: group_user.is_show_name,
                remark: group_user.remark,
                is_top: group_user.is_top,
                is_disturb: group_user.is_disturb,
                ext1: None,
                ext2: None,
                status: group_user.status.into(),
                create_time: Local::now(),
                is_waking: group_user.is_waking,
                update_time: Local::now(),
            };
            im_group_users.push(gu);
        }
        ImGroup {
            id: None,
            current_user_id: "".to_string(),
            code: self.group_id.clone(),
            server_id: Some(self.group_id),
            name: self.group_name,
            owner_id: self.owner_id,
            description: None,
            version: 0,
            group_type: ImGroupType::Chat,
            status: self.status.into(),
            ext1: None,
            ext2: None,
            first_letter: self.first_letter,
            create_time: Local::now(),
            update_time: Local::now(),
            group_users: Some(im_group_users),
        }
    }
}

impl Into<ImGroupStatus> for GroupStatus {
    fn into(self) -> ImGroupStatus {
        match self {
            GroupStatus::Disable => { ImGroupStatus::Disable }
            GroupStatus::Enable => { ImGroupStatus::Enable }
            GroupStatus::Dissolution => { ImGroupStatus::Dissolution }
            GroupStatus::Prohibition => { ImGroupStatus::Prohibition }
        }
    }
}

impl Into<ImGroupUserStatus> for GroupUserStatus {
    fn into(self) -> ImGroupUserStatus {
        match self {
            GroupUserStatus::Disable => { ImGroupUserStatus::Disable }
            GroupUserStatus::Enable => { ImGroupUserStatus::Enabled }
            GroupUserStatus::Exit => { ImGroupUserStatus::Dissolution }
            GroupUserStatus::Prohibition => { ImGroupUserStatus::Prohibition }
        }
    }
}
